package org.bangumibuddy.parser.impl;

import org.apache.commons.lang3.ArrayUtils;
import org.bangumibuddy.parser.AnimeMetaParser;
import org.bangumibuddy.pojo.anime.AnimeMetaData;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexPatternAnimeMetaParser implements AnimeMetaParser {

    private static final Pattern COLLECTION_EPISODE_PATTERN = Pattern.compile("\\d+-\\d+");
    private static final Pattern EPISODE_PATTERN = Pattern.compile("\\d+");
    private static final Pattern TITLE_PATTERN = Pattern.compile("(.*|\\[.*])( -? \\d+|\\[\\d+]|\\[\\d+.?[vV]\\d]|第\\d+[话話集]|\\[第?\\d+[话話集]]|\\[\\d+.?END]|[Ee][Pp]?\\d+|\\[\\d+-\\d+Fin]|\\[\\d+-\\d+]|\\(\\d+-\\d+Fin)(.*)");
    private static final Pattern RESOLUTION_PATTERN = Pattern.compile("1080|720|2160|4K");
    private static final Pattern SOURCE_PATTERN = Pattern.compile("B-Global|[Bb]aha|[Bb]ilibili|AT-X|Web");
    private static final Pattern SUB_PATTERN = Pattern.compile("[简繁日字幕]|CH|BIG5|GB");
    private static final Pattern PREFIX_PATTERN = Pattern.compile("[^\\w\\s\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff-]");
    private static final Pattern CHINESE_NUMBER_PATTERN = Pattern.compile("一|二|三|四|五|六|七|八|九|十");

    private static String getGroup(String name) {
        String[] parts = name.split("[\\[\\]]");
        return parts.length > 1 ? parts[1] : "";
    }

    private static String preProcess(String rawName) {
        return rawName.replace("【", "[").replace("】", "]");
    }

    private static String prefixProcess(String raw, String group) {
        raw = raw.replaceAll(".(" + group + ").", "");
        String rawProcessed = PREFIX_PATTERN.matcher(raw).replaceAll("/");
        String[] argGroup = rawProcessed.split("/");
        argGroup = Arrays.stream(argGroup).filter(s -> !s.isEmpty()).toArray(String[]::new);
        if (argGroup.length == 1) {
            argGroup = argGroup[0].split(" ");
        }
        for (String arg : argGroup) {
            if (Pattern.compile("新番|月?番").matcher(arg).find() && arg.length() <= 5) {
                raw = raw.replaceAll(".(" + arg + ").", "");
            } else if (Pattern.compile("港澳台地区").matcher(arg).find()) {
                raw = raw.replaceAll(".(" + arg + ").", "");
            }
        }
        return raw;
    }

    private static String[] seasonProcess(String seasonInfo) {
        seasonInfo = seasonInfo.replaceAll("[\\[\\]]", " ");
        String nameSeason = seasonInfo;
        Pattern seasonPattern = Pattern.compile("(S|s)\\d{1,2}|season \\d{1,2}|[第].[季期]|(S|s)\\d+|\\d{1,2}(st|nd|rd|th)\\s*(s|S)eason");
        Matcher seasonMatcher = seasonPattern.matcher(seasonInfo);
        List<String> seasonsList = new ArrayList<>();
        while (seasonMatcher.find()) {
            seasonsList.add(seasonMatcher.group());
        }
        if (seasonsList.isEmpty()) {
            return new String[]{nameSeason, "", "1"};
        }
        String name = seasonsList.stream().reduce(nameSeason, (result, season) -> result.replaceAll(season, ""));
        String seasonRaw = "";
        int seasonValue = 1;
        for (String season : seasonsList) {
            String seasonPro = season.replaceAll("(s|S)eason|[第季期sS ]|st|nd|rd|th", "");
            try {
                seasonValue = Integer.parseInt(seasonPro);
                seasonRaw = season;
                break;
            } catch (NumberFormatException e) {
                Map<String, Integer> chineseNumberMap = new HashMap<String, Integer>() {{
                    put("一", 1);
                    put("二", 2);
                    put("三", 3);
                    put("四", 4);
                    put("五", 5);
                    put("六", 6);
                    put("七", 7);
                    put("八", 8);
                    put("九", 9);
                    put("十", 10);
                }};
                if (chineseNumberMap.containsKey(seasonPro)) {
                    seasonValue = chineseNumberMap.get(seasonPro);
                    seasonRaw = season;
                    break;
                }
            }
        }
        return new String[]{name.strip(), seasonRaw, String.valueOf(seasonValue)};
    }

    private static String[] nameProcess(String name) {
        String nameEn = "";
        String nameZh = "";
        String nameJp = "";
        name = name.trim().replaceAll("[(（]仅限港澳台地区[）)]", "");
        String[] split = name.split("/|\\s{2}|-\\s{2}");
        List<String> splitList = new ArrayList<>(Arrays.asList(split));
        splitList.removeAll(Arrays.asList("", null));
        split = splitList.toArray(new String[0]);
        if (split.length == 1) {
            if (split[0].contains("_")) {
                split = split[0].split("_");
            } else if (split[0].contains(" - ")) {
                split = split[0].split(" - ");
            }
        }
        if (split.length == 1) {
            String[] splitSpace = split[0].split(" ");
            for (int idx : new int[]{0, splitSpace.length - 1}) {
                if (Pattern.compile("^[\u4e00-\u9fa5]{2,}").matcher(splitSpace[idx]).find()) {
                    String chs = splitSpace[idx];
                    splitSpace = ArrayUtils.removeElement(splitSpace, chs);
                    split = new String[]{chs, String.join(" ", splitSpace)};
                    break;
                }
            }
        }
        for (String item : split) {
            if (Pattern.compile("[\u0800-\u4e00]{2,}").matcher(item).find() && nameJp.isEmpty()) {
                nameJp = item.trim();
            } else if (Pattern.compile("[\u4e00-\u9fa5]{2,}").matcher(item).find() && nameZh.isEmpty()) {
                nameZh = item.trim();
            } else if (Pattern.compile("[a-zA-Z]{3,}").matcher(item).find() && nameEn.isEmpty()) {
                nameEn = item.trim();
            }
        }
        return new String[]{nameEn, nameZh, nameJp};
    }

    private static String[] findTags(String other) {
        String[] elements = other.replaceAll("[\\[\\]()（）]", " ").split(" ");
        String sub = null;
        String resolution = null;
        String source = null;
        for (String element : elements) {
            if (SUB_PATTERN.matcher(element).find()) {
                sub = element;
            } else if (RESOLUTION_PATTERN.matcher(element).find()) {
                resolution = element;
            } else if (SOURCE_PATTERN.matcher(element).find()) {
                source = element;
            }
        }
        return new String[]{cleanSub(sub), resolution, source};
    }

    private static String cleanSub(String sub) {
        if (sub == null) {
            return null;
        }
        return sub.replaceAll("_MP4|_MKV", "");
    }

    private static String[] process(String rawTitle) {
        rawTitle = rawTitle.trim();
        String contentTitle = preProcess(rawTitle);
        String group = getGroup(contentTitle);
        Matcher matcher = TITLE_PATTERN.matcher(contentTitle);
        if (!matcher.matches()) {
            return null;
        }
        String seasonInfo = matcher.group(1).trim();
        String episodeInfo = matcher.group(2).trim();
        String other = matcher.group(3).trim();
        String processRaw = prefixProcess(seasonInfo, group);
        String[] seasonData = seasonProcess(processRaw);
        String rawName = seasonData[0];
        String seasonRaw = seasonData[1];
        int season = Integer.parseInt(seasonData[2]);
        String[] nameData = nameProcess(rawName);
        String nameEn = nameData[0];
        String nameZh = nameData[1];
        String nameJp = nameData[2];
        Matcher episodeMatcher = EPISODE_PATTERN.matcher(episodeInfo);
        int episode = episodeMatcher.find() ? Integer.parseInt(episodeMatcher.group()) : 0;
        Matcher collection_episode_matcher = COLLECTION_EPISODE_PATTERN.matcher(episodeInfo);
        String collectionEpisode = collection_episode_matcher.find() ? "[" + collection_episode_matcher.group().trim() + "]" : ""; // [xx-xx]
        episode = COLLECTION_EPISODE_PATTERN.matcher(episodeInfo).find() ? -1 : episode; //如果是collection则episode为0
        String[] tags = findTags(other);
        String sub = tags[0];
        String dpi = tags[1];
        String source = tags[2];
        return new String[]{nameEn, nameZh, nameJp, String.valueOf(season), seasonRaw, String.valueOf(episode), sub, dpi, source, group, collectionEpisode};
    }

    public static AnimeMetaData rawParser(String raw) {
        String[] ret = process(raw);
        if (ret == null) {
            System.out.println("Parser cannot analyse " + raw);
            return null;
        }
        String nameEn = ret[0];
        String nameZh = ret[1];
        String nameJp = ret[2];
        int season = Integer.parseInt(ret[3]);
        String seasonRaw = ret[4];
        int episode = Integer.parseInt(ret[5]);
        String sub = ret[6];
        String dpi = ret[7];
        String source = ret[8];
        String group = ret[9];
        String collectionEpisode = ret[10];

        AnimeMetaData animeMetaData = new AnimeMetaData();
        animeMetaData.setGroup(group);
        animeMetaData.setTitle_zh(nameZh);
        animeMetaData.setTitle_en(nameEn);
        animeMetaData.setTitle_jp(nameJp);
        animeMetaData.setSeason(season);
        animeMetaData.setEpisode(episode);
        animeMetaData.setSource(source);
        animeMetaData.setCollectionEpisode(collectionEpisode);
        return animeMetaData;
    }

    @Override
    public AnimeMetaData parse(String filename) {
        return rawParser(filename);
    }
}
